package com.example.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Slf4j
@Component
//@Aspect
public class TimeAspect {

    //通知类型
    //1.@Before 前置通知: 在目标方法执行前执行
    //2.@After  后置通知: 在目标方法执行后执行,无论有没有异常都执行
    //3.@Around 环绕通知: 在目标方法执行前和后都执行一段逻辑
    //4.@AfterReturning 返回通知: 在目标方法正常返回后执行,有异常不执行
    //5.@AfterThrowing 异常通知: 在目标方法抛出异常后执行

    //AOP核心概念
    //1.连接点:JoinPoint, 可以被AOP控制的方法(暗含方法执行时相关的信息)
    //2.切入点:PointCut, 可以被AOP拦截的方法(可以自己定义)
    //3.通知:Advice, 在连接点执行的代码(可以自己定义)
    //4.切面:Aspect, 把通知和切入点组合在一起
    //5.目标对象:TargetObject, 被代理的对象
    //6.代理对象:ProxyObject, AOP框架创建的代理对象
    //7.织入:Weaving, 把通知和目标对象结合到代理对象中

    //AOP执行顺序
    //目标方法前的通知方法:字母排名靠前先执行
    //目标方法后的通知方法:字母排名靠前后执行
    //@Order: 值越小优先级越高

    //execution(访问修饰符 返回值类型 包名.类名.方法名(参数列表) throws 异常)
    //可省略访问修饰符 包名.类名(不建议) throws 异常
    //*: 匹配任意一个字符, 例如:execution(* com.*.*service.*.*(*))
    //..: 匹配任意数量任意类型的参数,任意层级的包, 例如:execution(* com..service..*.*(..))
    @Around("execution(* com.example.service.*.*(..))")//切入点表达式
    public Object recordTime(ProceedingJoinPoint proceedingJoinPoint){
        //1.记录开始时间
        long start = System.currentTimeMillis();
        //2.调用原始方法
        Object result = null;
        try {
            result =proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        //3.记录结束时间
        long end = System.currentTimeMillis();
        log.info("耗时:{}",end - start);

        return result;
    }
}

